<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>默认的图片节点</title>
  </head>
  <body>
    <div id="mountNode"></div>
    <div id="mountNode1"></div>
    <script src="../build/g6.js"></script>
    <script>
      const edgeTypeColorMap = {
        type1: ['#531dab', '#391085', '#391085'],
        type2: ['#d9d9d9', '#bfbfbf', '#8c8c8c'],
        type3: ['#d3adf7', '#b37feb', '#9254de'],
      };

      const generateArrow = lineWidth => {
        let width = (lineWidth * 4) / 3;
        return [
          ['M', lineWidth / 2, 0],
          ['L', -width * 1.5, -width * 1.5],
          ['L', -width * 1.5, width * 1.5],
          // ['A', radius, radius, 0, 0, 1, -width / 2, halfHeight],
          ['Z'],
        ];
      };

      const defaultConf = {
        style: {
          lineAppendWidth: 5,
          lineDash: [0, 0],
          lineDashOffset: 0,
          endArrow: true,
          opacity: 1,
          labelCfg: {
            style: {
              fillOpacity: 1,
            },
          },
        },
        /**
         * 绘制边
         * @override
         * @param  {Object} cfg   边的配置项
         * @param  {G.Group} group 边的容器
         * @return {G.Shape} 图形
         */
        drawShape(cfg, group) {
          const item = group.get('item');
          const shapeStyle = this.getShapeStyle(cfg, item);
          const shape = group.addShape('path', {
            className: 'edge-path',
            attrs: shapeStyle,
          });
          return shape;
        },
        drawLabel(cfg, group) {
          const labelCfg = cfg.labelCfg || {};
          const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
          const text = group.addShape('text', {
            attrs: {
              ...labelStyle,
              text: cfg.label,
              fontSize: 12,
              fill: '#404040',
              cursor: 'pointer',
            },
            className: 'edge-label',
          });

          return text;
        },

        /**
         * 获取图形的配置项
         * @internal 仅在定义这一类节点使用，用户创建和更新节点
         * @param  {Object} cfg 节点的配置项
         * @return {Object} 图形的配置项
         */
        getShapeStyle(cfg, item) {
          const { startPoint, endPoint } = cfg;
          const type = item.get('type');

          const defaultStyle = this.getStateStyle('default', true, item);

          if (type === 'node') {
            return Object.assign({}, cfg.style, defaultStyle);
          }

          const controlPoints = this.getControlPoints(cfg);
          let points = [startPoint]; // 添加起始点
          // 添加控制点
          if (controlPoints) {
            points = points.concat(controlPoints);
          }
          // 添加结束点
          points.push(endPoint);
          const path = this.getPath(points);

          const style = Object.assign({}, { path }, cfg.style, defaultStyle);
          return style;
        },
        getControlPoints(cfg) {
          let controlPoints = cfg.controlPoints; // 指定controlPoints

          if (!controlPoints || !controlPoints.length) {
            const { startPoint, endPoint } = cfg;
            const innerPoint = G6.Util.getControlPoint(
              startPoint,
              endPoint,
              0.5,
              cfg.edgeOffset || 30,
            );
            controlPoints = [innerPoint];
          }
          return controlPoints;
        },
        /**
         * 获取三次贝塞尔曲线的path
         *
         * @param {array} points 起始点和两个控制点
         * @returns
         */
        getPath(points) {
          const path = [];
          path.push(['M', points[0].x, points[0].y]);
          path.push(['Q', points[1].x, points[1].y, points[2].x, points[2].y]);
          return path;
        },
        /**
         * 根据不同状态，获取不同状态下的样式值
         * @param {string} name
         * @param {string} value
         * @param {Item} item
         */
        getStateStyle(name, value, item) {
          const model = item.getModel();
          const { style = {} } = model;

          const defaultStyle = Object.assign({}, this.style);

          // 更新颜色
          return {
            ...defaultStyle,
            lineWidth: 1,
            stroke: edgeTypeColorMap[model.edgeType] && edgeTypeColorMap[model.edgeType][0],
            ...style,
          };
        },
        /**
         * 拖动时更新path及边的label
         *
         * @param {object} cfg 边的model
         * @param {Edge} item 边的实例
         */
        update(cfg, item) {
          const { data, style, startPoint, endPoint, labelCfg = {} } = cfg;
          const group = item.getContainer();
          const model = data || cfg;

          let arrowWidth = 2;

          const defaultStyle = Object.assign(
            {},
            this.style,
            {
              lineWidth: 1,
              stroke: edgeTypeColorMap[model.edgeType] && edgeTypeColorMap[model.edgeType][0],
              endArrow: {
                path: generateArrow(arrowWidth),
              },
            },
            style,
          );

          const { opacity, onlyHideText } = defaultStyle;

          // 更新 path
          const keyShape = item.getKeyShape();

          const controlPoints = this.getControlPoints(cfg);

          keyShape.attr({
            path: [
              ['M', startPoint.x, startPoint.y],
              ['Q', controlPoints[0].x, controlPoints[0].y, endPoint.x, endPoint.y],
            ],
            ...defaultStyle,
          });

          const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
          const text = group.findByClassName('edge-label');
          const attrs = _.omit(
            {
              ...labelStyle,
              fillOpacity: onlyHideText ? 0 : opacity === 0 ? opacity : 1,
              fill: '#404040',
            },
            'stroke',
          );
          if (text) {
            text.resetMatrix();
            text.attr(attrs);
          }
        },
      };

      G6.registerEdge('quadratic-label-edge', defaultConf, 'quadratic');

      // let nodes = []
      //     for(let i = 0; i < 500; i++) {
      //       nodes.push({
      //         id: `node-${i}`,
      //         label: `label-${i}`,
      //         x: Math.random() * 650,
      //         y: Math.random() * 550
      //       })
      //     }
      const data = {
        nodes: [
          {
            id: 'node1',
            label: 'node1',
          },
          {
            id: 'node2',
            label: 'node2',
          },
        ],
        edges: [
          {
            source: 'node1',
            target: 'node2',
            edgeType: 'type1',
          },
          {
            source: 'node2',
            target: 'node1',
            edgeType: 'type2',
          },
          {
            source: 'node1',
            target: 'node2',
            edgeType: 'type3',
            edgeOffset: -10,
          },
        ],
      };

      const graph = new G6.Graph({
        container: 'mountNode',
        width: 800,
        height: 600,
        defaultNode: {
          shape: 'rect',
          size: [60, 30],
          color: 'green',
          style: {
            // fill: 'red',
            // stroke: '#eaff8f',
            lineWidth: 5,
          },
          labelCfg: {
            style: {
              fill: '#9254de',
              fontSize: 18,
            },
          },
          linkPoints: {
            top: true,
            bottom: true,
            left: true,
            right: true,
            size: 5,
            fill: '#fff',
          },
        },
        defaultEdge: {
          shape: 'quadratic-label-edge',
        },
        nodeStateStyles: {
          hover: {
            fill: '#d3adf7',
          },
        },
        modes: {
          default: [
            'drag-canvas',
            'drag-node',
            {
              type: 'brush-select',
              trigger: 'ctrl',
            },
          ],
        },
      });

      graph.data(data);
      graph.render();

      graph.on('node:click', evt => {
        const { item } = evt;
        graph.setItemState(item, 'select', true);
        graph.updateItem(item, {
          size: [260, 130],
          style: {
            opacity: 0.6,
          },
          preRect: {
            fill: 'blue',
          },
          linkPoints: {
            fill: '#fff',
            size: 5,
          },
          stateIcon: {
            img:
              'https://gw.alipayobjects.com/zos/basement_prod/c781088a-c635-452a-940c-0173663456d4.svg',
          },
        });
      });

      graph.on('node:mouseenter', evt => {
        const { item } = evt;
        graph.setItemState(item, 'hover', true);
      });

      graph.on('node:mouseleave', evt => {
        const { item } = evt;
        graph.setItemState(item, 'hover', false);
      });

      // graph.addItem('group', {
      //   nodes: ['image', 'triangle'],
      //   type: 'rect',
      //   zIndex: 0,
      //   title: {
      //     text: '名称'
      //   }
      // })
    </script>
  </body>
</html>
